package middlewares

import (
	"bytes"
	"encoding/json"
	"strings"
	"time"

	"gitee.com/xgotool/backend-framework-template/config"
	"gitee.com/xgotool/backend-framework-template/model/modellog"
	"gitee.com/xiaoyutab/xgotool/xnum"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
)

type bodyLogWriter struct {
	gin.ResponseWriter
	body *bytes.Buffer
}

// 写字节
func (w bodyLogWriter) Write(b []byte) (int, error) {
	w.body.Write(b)
	return w.ResponseWriter.Write(b)
}

// 读字节
func (w bodyLogWriter) WriteString(s string) (int, error) {
	w.body.WriteString(s)
	return w.ResponseWriter.WriteString(s)
}

// 返回值结构体
type responeData struct {
	Code int    `json:"code"`
	Data any    `json:"request"`
	Flag bool   `json:"flag"`
	Msg  string `json:"msg"`
}

// 记录log模块的请求日志
//
//	c	gin上下文请求
func Log(c *gin.Context) {
	// 开始时间
	startTime := time.Now()
	// 处理请求
	c.Next()
	// 记录返回值
	bodyLogWriter := &bodyLogWriter{body: bytes.NewBufferString(""), ResponseWriter: c.Writer}
	c.Writer = bodyLogWriter
	var param any
	switch c.ContentType() {
	case "application/json":
		c.Copy().ShouldBindBodyWith(&param, binding.JSON)
	case "application/xml":
		c.Copy().ShouldBindBodyWith(&param, binding.XML)
	default:
		param = c.Request.PostForm
	}
	// 结束时间
	endTime := time.Now()
	// 执行时间
	latencyTime := endTime.Sub(startTime)
	// 请求参数格式化
	p, _ := json.Marshal(param)
	// 返回值格式化
	respone := responeData{}
	json.Unmarshal(bodyLogWriter.body.Bytes(), &respone)
	body, _ := json.Marshal(respone.Data)
	// 记录日志
	header_quest := map[string][]string{}
	for k, v := range c.Request.Header {
		// 忽略header值【在此列表中的将不会记入日志】
		if !xnum.InArray(strings.ToLower(k), []string{
			"accept", "accept-encoding", "accept-language",
			"connection", "content-type", "dnt",
			"origin", "referer",
			"sec-ch-ua", "sec-ch-ua-mobile", "sec-ch-ua-platform", "sec-fetch-dest", "sec-fetch-mode", "sec-fetch-site", "sec-gpc",
		}) {
			header_quest[k] = v
		}
	}
	headers, _ := json.Marshal(header_quest)
	if conn, err := config.Log(); err == nil {
		log := modellog.QuestLog{
			Uri:       c.Request.RequestURI,
			Param:     string(p),
			HttpCode:  int64(c.Writer.Status()),
			Body:      string(body),
			Error:     respone.Msg,
			Header:    string(headers),
			QuestSec:  latencyTime.Nanoseconds(),
			ClientIp:  c.ClientIP(),
			Uid:       c.GetUint("uid"),
			CreatedAt: time.Now().Unix(),
		}
		go conn.Table(log.TableName()).Create(&log)
	}
}
